/**
 * 
 */
package stc.skymobi.launcher;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
 * @author Marvin.Ma
 *
 */
public class Main {

	private static String jarFilename2UnzipPath(String jarFilename) {
		int idx = jarFilename.lastIndexOf(".");
		if ( -1 != idx ) {
			return	jarFilename.substring(0, idx) + "/";
		}
		else {
			return	jarFilename;
		}
	}
	
	private static boolean isUnzipedExist(String unzipedPath) {
		File path = new File(unzipedPath);
		
		return path.exists() && path.isDirectory();
	}
	
    private static void unzipJar(String jarFilename, String unzipBasePath) throws IOException {
    	final int BUFFER_SIZE = 4096;
    	
    	ZipFile	zipFile = null;
    	
    	try {
    		//	eg. c:/units/jars/rop-mis.zip

    		//	eg. mkdir c:/units/jars/rop-mis/
            new File( unzipBasePath ).mkdirs();
            
			zipFile = new ZipFile(jarFilename);
			
			//	解压zip file
			Enumeration<? extends ZipEntry> emu = zipFile.entries();
            while(emu.hasMoreElements()){
                ZipEntry entry = emu.nextElement();
                //会把目录作为一个file读出一次，所以只建立目录就可以，之下的文件还会被迭代到。
                if (entry.isDirectory())
                {
                    new File( unzipBasePath + entry.getName()).mkdirs();
                    continue;
                }
                BufferedInputStream bis = new BufferedInputStream(zipFile.getInputStream(entry));
                File file = new File(unzipBasePath + entry.getName());
                
                //	加入这个的原因是zipfile读取文件是随机读取的，这就造成可能先读取一个文件
                //	而这个文件所在的目录还没有出现过，所以要建出目录来。
                File parent = file.getParentFile();
                if(parent != null && (!parent.exists())){
                    parent.mkdirs();
                }
                
                FileOutputStream fos = new FileOutputStream(file);
                BufferedOutputStream bos = new BufferedOutputStream(fos, BUFFER_SIZE);
                
                int count;
                byte data[] = new byte[BUFFER_SIZE];
                while ((count = bis.read(data, 0, BUFFER_SIZE)) != -1)
                {
                    bos.write(data, 0, count);
                }
                bos.flush();
                bos.close();
                bis.close();
            }
	    	
		} 
		finally {
			if ( null != zipFile ) {
	            try {
					zipFile.close();
				} catch (IOException e) {
					System.out.println("failed to close zip file " + jarFilename + ", reason " + e );
				}
			}
		}
    }
    
    private static boolean isJarfileEqualsUnziped(String jarFilename, String unzipedPath) {
    	final int BUFFER_SIZE = 4096;
    	
    	JarFile jar = null;
    	byte[] zipedManifestConetnt = null, unzipedManifestContent = null;
    	
    	try {
	    	jar = new JarFile(jarFilename);
			Manifest manifest = jar.getManifest();
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			manifest.write(baos);
			zipedManifestConetnt = baos.toByteArray();
    	}
    	catch (Exception e) {
    		System.out.println("failed to get jarFilename " + jarFilename + " version, reason " + e);
    		return	false;
    	}
    	finally {
    		if ( null != jar ) {
    			try {
					jar.close();
				} catch (IOException e) {
		    		System.out.println("failed to close jarFilename " + jarFilename + ", reason " + e);
				}
    		}
    	}
    	
    	try {
	    	String unzipedManifestPath = unzipedPath + "META-INF/MANIFEST.MF";
	    	File unzipedManifest = new File(unzipedManifestPath);
	    	if ( !unzipedManifest.exists() ) {
	    		System.out.println("unziped manifest " + unzipedManifestPath 
	    				+ " not exists");
	    		return	false;
	    	}
			ByteArrayOutputStream baosUnziped = new ByteArrayOutputStream();
			BufferedInputStream bis = new BufferedInputStream(
					new FileInputStream(unzipedManifest), BUFFER_SIZE);
	        int count;
	        byte data[] = new byte[BUFFER_SIZE];
	        while ((count = bis.read(data, 0, BUFFER_SIZE)) != -1)
	        {
	        	baosUnziped.write(data, 0, count);
	        }
	        unzipedManifestContent = baosUnziped.toByteArray();
    	}
    	catch (Exception e) {
    		System.out.println("failed to get zuniped  " + jarFilename + " version, reason " + e);
    		return	false;
    	}
    	
    	 return	Arrays.equals(zipedManifestConetnt, unzipedManifestContent);
    }
    
	private static void deleteDir(File dir) {
		if (dir == null || !dir.exists() || !dir.isDirectory())
			return; // 检查参数

		for (File file : dir.listFiles()) {
			if (file.isFile()) {
				file.delete(); // 删除所有文件
			} else if (file.isDirectory()) {
				deleteDir(file); // 递规的方式删除文件夹
			}
		}
		dir.delete();// 删除目录本身
	}
    
    private static void removeUnziped(String unzipedPath) {
    	deleteDir(new File(unzipedPath));
    }
    
    private static String getRunCmd(String jarFilename) {
    	String runCmd = null;
    	JarFile jar = null;
    	
    	try {
	    	jar = new JarFile(jarFilename);
			Manifest manifest = jar.getManifest();
			runCmd = manifest.getMainAttributes().getValue("Run-Cmd");
    	}
    	catch (Exception e) {
    		System.out.println("failed to get runcmd from  " + jarFilename + ", reason " + e);
    	}
    	finally {
    		if ( null != jar ) {
    			try {
					jar.close();
				} catch (IOException e) {
		    		System.out.println("failed to close jarFilename " + jarFilename + ", reason " + e);
				}
    		}
    	}
    	
    	return	runCmd;
    }
    
	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		String userDir = System.getProperty("user.dir");
		String appName = System.getProperty("app.name");
		
		String jarFilename = userDir + "/" + appName + ".jar";
		
		if ( !isUnzipedExist( jarFilename2UnzipPath(jarFilename) ) ) {
			System.out.println( "unziped not exist, unzip jar " + jarFilename + "." );
			unzipJar(jarFilename, jarFilename2UnzipPath(jarFilename) );
		}
		else {
			System.out.println(jarFilename2UnzipPath(jarFilename) + " already exist, try to verify.");
			if (isJarfileEqualsUnziped(jarFilename, jarFilename2UnzipPath(jarFilename))) {
				System.out.println( jarFilename + " equals unziped path " 
						+ jarFilename2UnzipPath(jarFilename) );
			}
			else {
				System.out.println( jarFilename + " !NOT! equals unziped path " 
						+ jarFilename2UnzipPath(jarFilename) + ", try remove unziped..." );
				removeUnziped(jarFilename2UnzipPath(jarFilename));
				System.out.println( "unzip jar " + jarFilename + " again." );
				unzipJar(jarFilename, jarFilename2UnzipPath(jarFilename) );
			}
		}
		String runCmd = getRunCmd(jarFilename);
		if ( null == runCmd ) {
			System.out.println( "can't find run cmd from " + jarFilename + ", just quit.");
			System.exit(-1);
		}
		
		System.out.println( "try to run " + jarFilename + " with cmd:" + runCmd);
		Process process = Runtime.getRuntime().exec(runCmd);
		System.out.println( "stop launch for " + jarFilename);
	}

}
